package edu.cuit.zhuyimeng.flight.service.impl;

import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheInvalidate;
import com.alicp.jetcache.anno.CacheInvalidateContainer;
import com.baomidou.dynamic.datasource.annotation.Master;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import edu.cuit.zhuyimeng.aircraft.api.controller.AircraftQueryController;
import edu.cuit.zhuyimeng.aircraft.api.dto.AircraftInfoDTO;
import edu.cuit.zhuyimeng.flight.controller.dto.CreateFlightDTO;
import edu.cuit.zhuyimeng.flight.controller.vo.FlightInfoVO;
import edu.cuit.zhuyimeng.flight.convert.FlightConverter;
import edu.cuit.zhuyimeng.flight.dal.mapper.FlightMapper;
import edu.cuit.zhuyimeng.flight.dal.po.FlightPO;
import edu.cuit.zhuyimeng.flight.enums.CacheConstants;
import edu.cuit.zhuyimeng.flight.service.IFlightDispatchService;
import edu.cuit.zhuyimeng.flight.service.IFlightQueryService;
import edu.cuit.zhuyimeng.framework.cache.aspect.annotation.CacheInvalidatePattern;
import edu.cuit.zhuyimeng.framework.common.exception.QueryException;
import edu.cuit.zhuyimeng.framework.common.result.CommonResult;
import edu.cuit.zhuyimeng.framework.common.system.enums.FlightStatus;
import edu.cuit.zhuyimeng.flight.service.IFlightManagerService;
import edu.cuit.zhuyimeng.framework.common.system.enums.SysConstants;
import edu.cuit.zhuyimeng.framework.common.exception.UpdateException;
import edu.cuit.zhuyimeng.framework.logging.aspect.annotation.OperateLog;
import edu.cuit.zhuyimeng.framework.logging.aspect.enums.OperateLogType;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import tech.powerjob.client.PowerJobClient;

import java.util.*;

/**
 * 航班管理服务实现类
 */
@Service
@RequiredArgsConstructor
public class FlightManagerService implements IFlightManagerService {

    private final FlightMapper flightMapper;
    private final AircraftQueryController aircraftQueryController;

    private final IFlightDispatchService flightDispatchService;
    private final IFlightQueryService flightQueryService;

    private final Cache<Long, FlightInfoVO> flightInfoCache;
    private final Cache<String, List<Long>> specificFlightInfoCache;

    private final RuntimeService runtimeService;

    private final PowerJobClient powerJobClient;

    @Override
    @OperateLog(module = "flight-service",name = "创建航班",type = OperateLogType.CREATE)
    @GlobalTransactional
    @Master
    public void createFlight(CreateFlightDTO createFlightDTO) {
        if (createFlightDTO.getStartBook().before(new Date())) {
            throw new UpdateException("开放订票时间不能早于当前时间");
        }
        if (createFlightDTO.getStartTime().before(createFlightDTO.getEndBook())) {
            throw new UpdateException("起飞时间不能早于关闭订票时间");
        }

        if (createFlightDTO.getStartBook().after(createFlightDTO.getEndBook())) {
            throw new UpdateException("开放订票时间应在关闭订票时间之前");
        }
        if (createFlightDTO.getStartTime().after(createFlightDTO.getEndTime())) {
            throw new UpdateException("起飞时间应在降落时间之前");
        }
        FlightPO flightPOTemp = flightMapper.selectOne(new LambdaQueryWrapper<FlightPO>().eq(FlightPO::getNumber, createFlightDTO.getNumber()));
        if (flightPOTemp != null) {
            throw new UpdateException("航班号已存在");
        }
        CommonResult<AircraftInfoDTO> aircraftInfo = aircraftQueryController.getAircraftInfo(createFlightDTO.getAircraftId());
        if (aircraftInfo.isError()) {
            throw new QueryException(aircraftInfo.getMsg());
        }
        if (aircraftInfo.getData().getIsLocked()) {
            throw new UpdateException("该飞机已被占用");
        }
        FlightPO flightPO = FlightConverter.createFlightDTOToFlightPO(createFlightDTO);
        flightMapper.insert(flightPO);
        flightDispatchService.initFlight(flightPO);
    }

    @Override
    @OperateLog(module = "flight-service",name = "删除航班",type = OperateLogType.DELETE)
    @Master
    public void adminRemoveFlight(Long id) {
        FlightInfoVO flightInfoVO = flightQueryService.queryOneFlight(id);
        if (flightInfoVO == null) {
            throw new UpdateException("此航班不存在");
        }
        int status = flightInfoVO.getStatus();
        if (status != FlightStatus.PREPARING.getType() && status != FlightStatus.ENDED.getType()) {
            throw new UpdateException("当前阶段不能执行删除阶段");
        }
        removeFlight(id);
    }

    @Override
    @CacheInvalidateContainer({
            @CacheInvalidate(name = CacheConstants.FLIGHT_INFO,key = "args[0]"),
            @CacheInvalidate(name = CacheConstants.FLIGHT_AMOUNT,key = "'all'")
    })
    @CacheInvalidatePattern(name = CacheConstants.PAGE_FLIGHT_INFO,pattern = "*")
    @Master
    public void removeFlight(Long id) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceBusinessKey(String.valueOf(id))
                .includeProcessVariables()
                .singleResult();
        Map<String, Object> processVariables = processInstance.getProcessVariables();
        powerJobClient.deleteJob((Long) processVariables.get(SysConstants.JOB_ID_KEY));
        flightMapper.delete(new LambdaQueryWrapper<FlightPO>().eq(FlightPO::getId,id));
        powerJobClient.deleteJob((Long) processVariables.get(SysConstants.JOB_ID_KEY));
        flightDispatchService.destroyFlight(id);
    }

    @Override
    public void refreshFlightCache(Long id) {
        FlightInfoVO flightInfoVO = flightQueryService.queryOneFlight(id);
        specificFlightInfoCache.remove(flightInfoVO.getCacheKey());
        flightInfoCache.remove(id);
    }
}
